# gozerbot/eventbase.py
#
#

""" 
    This module implements the EventBase class from which all other 
    events inherit. 

"""

__status__ = "seen"

## gozerbot imports

from utils.log import rlog
from utils.generic import stripident, fix_format, fromenc, toenc
from utils.lazydict import LazyDict
from utils.xmldict import XMLDict
from gozerbot.stats import stats
from gozerbot.config import config

## basic imports

import time
import re
import types
import copy

## simplejson import

from simplejson import loads, dumps

## defines1

cpy = copy.deepcopy

## makeargrest function

def makeargrest(event):
    """ set arguments and rest attributes of an event. """
    try: event.args = event.txt.split()[1:]
    except ValueError: event.args = []
    try: cmnd, event.rest = event.txt.split(' ', 1)
    except ValueError: event.rest = ""   
    event.command = event.txt.split(' ')[0]

## EventBase class

class EventBase(XMLDict):
    """ Base class for all events. Inherit from this. """


    def __init__(self, event={}, bot=None):
        self.server = ""
        XMLDict.__init__(self)
        self.threaded = False
        self.onlyqueues = False
        self.orig = event # the original data .. SET BY HANDLER 
        self.type = 'chat' # type of event
        self.cbtype = '' # callback type
        self.jabber = False # set if event is jabber event
        self.groupchat = False # set if event is groupchat
        self.botoutput = False # set if event is bot output
        self.cmnd = None # the event command
        self.prefix = u"" # txt before the command
        self.postfix = u"" # txt after the command
        self.target = u"" # target to give reponse to
        self.arguments = [] # arguments of event
        self.nick = u"" # nick of user originating the event 
        self.user = u""  # user originating the event
        self.ruserhost = u"" # real userhost 
        self.userhost = u"" # userhost that might change
        self.stripped = u"" # stripped JID 
        self.resource = u"" # resource part of JID
        self.origin = u"" # source of the event
        self.origchannel = u"" # original channel
        self.channel = u"" # channel .. might change
        self.origtxt = u"" # original txt
        self.txt = u"" # text .. might change
        self.command = u"" # the bot command if any
        self.remoteout = u""
        self.remotecmnd = False
        self.usercmnd = False
        self.alias = u"" # set to alias if one is used
        self.aliased = u"" # set if commadn is aliased
        self.time = time.time() # event creation time
        self.msg = False # set if event is a private message
        self.args = [] # arguments of command
        self.rest = u"" # txt following the command
        self.usercmnd = 0 # set if event is a command
        self.bot = bot # the bot where the event originated on
        self.sock = None # socket (set in DCC chat)
        self.allowqueue = True # allow event to be used in pipeline
        self.closequeue = True # cloase event queues when execution has ended
        self.inqueue = None # queue used as input in pipeline
        self.queues = [] # output queues (only used when set)
        self.printto = None # target to printto
        self.speed = 0 # speed with which this event needs to be processed
        self.groups = None # set if event triggers a RE callback
        self.cc = u"" # control character
        self.jid = None # JID of used originating the event
        self.jidchange = None # set is event changes jid
        self.conn = None # connection of bot originating the event
        self.denied = False # set if command is denied
        self.iscallback = False
        self.isresponse = False # set if event is a reponse
        self.isrelay = False
        self.isremote = False
        self.isdcc = False # set if event is DCC related
        self.isctcp = False # set if event is an ACTION
        self.options = LazyDict() # options dict on the event
        self.optionset = [] # list of options set
        self.filter = [] # filter list to use on output
        # xmpp stuff
        self.host = self.server
        self.xml = u""
        self.realjid = u""
        self.fromm = u""
        self.to = u""
        self.type = u""
        self.id = 0
        self.subject = u""
        self.body = u""
        self.error = u""
        self.errorcode = u""
        self.html = u""
        self.thread = u""
        self.x = {}
        if event: self.copyin(event)
        self.toirc() 
        stats.up('events', 'created')

    def __copy__(self):
        return EventBase(self)

    def __deepcopy__(self, bla):
        return EventBase(self)

    def toirc(self):
        """ set ircevent compat attributes. """
        self.jidchange = False
        self.cmnd = 'Message'
        try: self.resource = self.fromm.split('/')[1]
        except IndexError: pass
        self.channel = self['fromm'].split('/')[0]
        self.origchannel = self.channel
        self.nick = self.resource
        #try:
        #    self.jid = bot.jids[self.channel][self.resource]
        #    self.jidchange = True
        #except KeyError:
        #     pass
        self.jid = self.fromm
        self.ruserhost = self.jid
        self.userhost = self.jid
        self.stripped = self.jid.split('/')[0]
        self.printto = self.channel
        self.target = self.printto
        if self.sublements:
            for node in self.subelements:
                try: self.txt = node.body.data
                except (AttributeError, ValueError): continue
        self.origtxt = self.txt
        self.time = time.time()
        if self.type == 'groupchat':
            self.groupchat = True
            if self.jidchange: self.userhost = self.stripped
        else:
            self.groupchat = False
            self.userhost = self.stripped
        self.msg = not self.groupchat

    def copyin(self, ievent):
        """ copy in an event. """
        self.update(ievent)
        if ievent.has_key('options'): self.options = dict(ievent.options)        
        if ievent.has_key('queues'): self.queues = list(ievent.queues)
        return self

    def filtered(self, txt):
        """ see if txt if filtered on this event. """
        if not self.filter: return False
        for filter in self.filter:
            if filter in txt: return False
        return True

    def parse(self, bot, rawstr):
        """ parse raw string into event.  overload this. """
        pass

    def make_response(self, txt, result=None, nick=None, dot=False, nritems=False, nr=False, fromm=None, private=False, how=''):
        """ create a response based on txt and result list. """
        if result == []: return
        stats.up('events', 'replies')
        if not how:
            try: how = self.options['--how']        
            except KeyError: how = 'msg'
        restxt = ""
        splitted = []
        if type(result) == types.DictType:
            for i, j in result.iteritems():
                if type(j) == types.ListType:
                    try: z = ' .. '.join(j)
                    except TypeError: z = unicode(j)
                else: z = j
                res = "%s: %s" % (i, z)
                splitted.append(res)
                if dot == True: restxt += "%s%s" % (res, ' .. ')
                else: restxt += "%s %s" % (dot or ' ', res)
            if restxt:
                if dot == True: restxt = restxt[:-6]
                elif dot: restxt = restxt[:-len(dot)]
        lt = False # set if result is list
        if type(txt) == types.ListType and not result:
            result = txt
            origtxt = u""
            lt = True
        else: origtxt = txt
        if result: lt = True
        if self.queues:
            for i in self.queues:
                if splitted:
                    for item in splitted: i.put_nowait(item)
                elif restxt: i.put_nowait(restxt)
                elif lt:
                    for j in result: i.put_nowait(j)
                else: i.put_nowait(txt)
                if self.onlyqueues: return
        if not self.bot:
            rlog(10, 'event', 'no bot defined in event')
            return "no bot is defined in this event"
        pretxt = origtxt
        if lt and not restxt:
            res = []
            for i in result:
                if type(i) == types.ListType or type(i) == types.TupleType:
                    try: res.append(u' .. '.join(i))
                    except TypeError: res.extend(i)
                else: res.append(i)
            result = res
            if nritems:
                if len(result) > 1: pretxt += "(%s items) .. " % len(result)
            txtlist = result
            if not nr is False:
                try: start = int(nr)
                except ValueError: start = 0
                txtlist2 = []
                teller = start
                for i in txtlist:
                    txtlist2.append(u"%s) %s" % (teller, i))
                    teller += 1
                txtlist = txtlist2
            txtl = []
            for item in txtlist: txtl.append(toenc(item))
            txtlist = txtl
            if dot == True: restxt = ' .. '.join(txtlist)
            elif dot: restxt = dot.join(txtlist)
            else: restxt = ' '.join(txtlist)
        if pretxt:
            try: restxt = pretxt + restxt
            except TypeError: rlog(10, 'eventbase', "can't add %s and %s" % (str(pretxt), str(restxt)))
        if self.filtered(restxt): return
        if restxt: return restxt
        else: return "no data found"

    def reply(self, *args, **kwargs):
        """ reply to event. """
        resp = self.make_response(*args, **kwargs)
        if not resp: return
        self.bot.say(self.channel, resp)

    def missing(self, txt):
        """ show what arguments are missing. """
        stats.up('events', 'missing')
        if self.origtxt:
            splitted = self.origtxt.split()
            if self.bot.nick in splitted[0]:
                try: cmnd = splitted[1]
                except IndexError: cmnd = splitted[0]
            elif 'cmnd' in splitted[0]:
                try: cmnd = splitted[2]
                except IndexError: cmnd = splitted[0]
            else:
                if self.msg: cmnd = splitted[0]
                else:
                    if self.aliased: cmnd = self.aliased
                    else: cmnd = splitted[0][1:]
            self.reply(cmnd + ' ' + txt)
        else: self.reply('missing origtxt: %s' % txt)

    def ircstr(self):
        """ old compat function. use str() now. """
        return str(self)

    def handle_error(self, data):
        """ function to handler errors. .. overload this. """
        rlog(10, self.name.error, 'ERROR: %s' % str(data))

    def done(self, txt=None):
        """ reply with the txt 'done'. """
        if txt: self.reply('%s done' % txt)
        else: self.reply('done')

    def tojson(self):
        """ convert the event to a json string. """
        new = cpy(self)
        new.sock = 'setremote'
        new.bot = 'setremote'
        new.request = 'setremote'
        new.response = 'setremote'
        new.queues = []
        result = dumps(new)
        rlog(0, 'eventbase', 'tojson - %s' % str(result))
        return result

    def fromjsonstring(self, input):
        """ reconstruct the event from a jsonstring. """
        temp = loads(input)
        rlog(10, 'eventbase', str(temp))
        self.update(temp)
        return self

    def checkqueues(self, resultlist):
        """ check if resultlist is to be sent to the queues. if so do it. """
        if self.queues:
            for queue in self.queues:
                for item in resultlist: queue.put_nowait(item)
            return True

    def subelement(self, name):
       if self.subelements:
            rlog(10, 'eventbase', "got subelements")
            for node in self.subelements:
                try:
                    attr = getattr(node, name)
                    rlog(10, 'eventbase', "got subelement %s" % (name, str(attr)))
                    return attr.data
                except (AttributeError, TypeError): continue   

## defines2

defaultevent = EventBase()
